﻿using JuCloudy.Rsa;
using NHibernate;
using NHibernate.Linq;
using System;
using System.Linq;
using System.Security.Cryptography;
using System.Text;

namespace JuCloudy.Data.Nhibernate
{
    public class RsaContainer 
    {
        private static global::NHibernate.Cfg.Configuration mCfg = null;
        private static global::NHibernate.ISessionFactory SessionFactory = null;

        public RsaContainer()
        {
            mCfg = new NHibernate.Cfg.Configuration().Configure(
               System.Web.HttpContext.Current.Server.MapPath(
                    System.Configuration.ConfigurationManager.AppSettings["RsaNhCfg"]
                    ));

            SessionFactory = null;

            mCfg.AddClass(typeof(JuCloudy.Data.Entity.RsaInfo));
            mCfg.AddClass(typeof(JuCloudy.Data.Entity.RsaContent));
            SessionFactory = mCfg.BuildSessionFactory();
        }

        /// <summary>
        /// 生成Rsa Key并返回RsaId,参数out公钥
        /// </summary>
        /// <param name="PublicKey">公钥</param>
        /// <returns>RsaId</returns>
        public String GeneralKey(String IpAddress,out String PublicKey)
        {
            RSACryption rsa = new RSACryption();
            String xmlKey = ""; String xmlPubKey = "";
            rsa.RSAKey(out xmlKey, out xmlPubKey);
            using (NHibernate.ISession session = SessionFactory.OpenSession())
            {
                using (NHibernate.ITransaction vTransaction = session.BeginTransaction())
                {
                    JuCloudy.Data.Entity.RsaInfo entity = new Entity.RsaInfo()
                    {
                        Createdate = DateTime.Now,
                        IsIdle = false,
                        KeyId = Guid.NewGuid().ToString(),
                        LastOperate = "Create",
                        LastOperateDatetime = DateTime.Now,
                        OnlyPub = xmlPubKey,
                        WithPri = xmlKey,
                        LastOperateIpAddress = IpAddress
                    };
                    try
                    {
                        session.Save(entity);
                        vTransaction.Commit();
                        vTransaction.Dispose();
                        session.Flush();
                        session.Close();
                        session.Dispose();
                        PublicKey = entity.OnlyPub;
                        return entity.KeyId;
                    }
                    catch (Exception ex)
                    {
                        vTransaction.Rollback();
                        vTransaction.Dispose();
                        session.Flush();
                        session.Close();
                        session.Dispose();
                        throw ex;
                    }
                }
            }
        }

        /// <summary>
        /// 通过RsaId获取密钥，参数OnlyPub规定返回值的内容
        /// </summary>
        /// <param name="RsaId">密钥ID</param>
        /// <param name="OnlyPub">指示知否只返回公钥</param>
        /// <returns>密钥</returns>
        public String GetRsaKey(String RsaId, bool OnlyPub)
        {
            using (ISession session = SessionFactory.OpenSession())
            {
                var query = session.Query<JuCloudy.Data.Entity.RsaInfo>().First(p => p.KeyId == RsaId);

                session.Flush();
                session.Close();
                session.Dispose();
                if (OnlyPub)
                {
                    return query.OnlyPub;
                }
                else
                {
                    return query.WithPri;
                }
            }
        }

        /// <summary>
        /// 获取已存在的加密数据
        /// </summary>
        /// <param name="RsaId">密钥Id</param>
        /// <returns>已存在的加密数据</returns>
        public String GetRsaContent(String RsaId)
        {
            using (ISession session = SessionFactory.OpenSession())
            {
                var query = session.Query<JuCloudy.Data.Entity.RsaContent>().First(p => p.RsaId == RsaId);

                session.Flush();
                session.Close();
                session.Dispose();

                return query.ContentChar;
            }
        }

        /// <summary>
        /// 通过公钥加密内容，无返回值，需提供RsaId、公钥和需加密的数据
        /// </summary>
        /// <param name="RsaId">密钥Id</param>
        /// <param name="PublicKey">公钥</param>
        /// <param name="Content">需加密的内容</param>
        /// <param name="IpAddress">执行此操作端的IP地址</param>
        public void Encrypt(String RsaId, String PublicKey, String Content, String IpAddress)
        {
            RSACryption rsa = new RSACryption();
            using (NHibernate.ISession session = SessionFactory.OpenSession())
            {
                using (NHibernate.ITransaction vTransaction = session.BeginTransaction())
                {
                    String buffer = rsa.RSAEncrypt(PublicKey, Content);
                    JuCloudy.Data.Entity.RsaContent entity= new Entity.RsaContent()
                    {
                        ContentChar =buffer,
                        RsaId = RsaId,
                        LastUpdataDate = DateTime.Now,
                        LastUpdataIPAddress = IpAddress
                    };
                    if (entity.UpdateTimes == null)
                        entity.UpdateTimes = 0;
                    else
                        entity.UpdateTimes = entity.UpdateTimes + 1;


                    try
                    {
                        session.Save(entity);
                        vTransaction.Commit();
                        vTransaction.Dispose();
                        session.Flush();
                        session.Close();
                        session.Dispose();
                    }
                    catch (Exception ex)
                    {
                        vTransaction.Rollback();
                        vTransaction.Dispose();
                        session.Flush();
                        session.Close();
                        session.Dispose();
                        throw ex;
                    }
                }
            }
        }

        /// <summary>
        /// 通过私钥解密内容，返回解密内容，需提供RsaId和需解密的数据
        /// </summary>
        /// <param name="RsaId">密钥Id</param>
        /// <param name="Content">需解密的数据</param>
        /// <returns>解密数据</returns>
        public String Decrypt(String RsaId, String Content)
        {
            String RsaKey = GetRsaKey(RsaId, false);
            RSACryption rsa = new RSACryption();
            return rsa.RSADecrypt(RsaKey, Content);
        }

        /// <summary>
        /// 通过RsaId解密已存在的加密数据
        /// </summary>
        /// <param name="RsaId">密钥Id</param>
        /// <returns>解密数据</returns>
        public String DecryptByRsaId(String RsaId)
        {
            var RsaContent = GetRsaContent(RsaId);
            return Decrypt(RsaId, RsaContent);
        }

    }
}
